/** TS设计可以做类型编程的类型提供目的是为了产生各种复杂的类型，所以就需要 重新构造 */

// ------------------------------------- 数组类型 -----------------------------------------------
// 数组的Push
type GetPush<Arr extends unknown[], Val> = [...Arr, Val];
type GetPushR = GetPush<[1, 2, 3], 4>;

// 数组的Unshift
type GetUnshift<Arr extends unknown[], Val> = [Val, ...Arr];
type GetUnshiftR = GetUnshift<[1, 2, 3], 4>

/** 两个元祖(注意这里是元祖，不是数组)
 * type tuple1 = [1, 2];
 * type tuple2 = ["guang", "dong"]
 * 合并成
 * type tuple = [[1, "guang"], [2, "dong"]]
 */
type GetZip<Tuple1 extends [unknown, unknown], Tuple2 extends [unknown, unknown]> = Tuple1 extends [infer V11, infer V12] ? Tuple2 extends [infer V21, infer V22] ? [[V11, V21], [V12, V22]] :[] : []
type tuple1 = [1, 2];
type tuple2 = ["guang", "dong"]
type GetZipR = GetZip<tuple1, tuple2>;

// 上面是固定长度，如果是任意的呢？也就是数组
type GetZip1<Tuple1 extends unknown[], Tuple2 extends unknown[]> = Tuple1 extends [infer V1, ...infer O1] ? Tuple2 extends [infer V2, ...infer O2] ? [[V1, V2], ...GetZip1<O1, O2>] : [] : []
type tuple3 = [1, 2, 12 ,3];
type tuple4 = ["guang", "dong", "1", "3"]
type GetZip1R = GetZip1<tuple3, tuple4>;

// ------------------------------------- 字符串类型 -----------------------------------------------
// 让字符串首字母大写
type GetCapitalizeStr<Str extends string> = Str extends `${infer P}${infer O}` ? `${Uppercase<P>}${O}` : Str;
type GetCapitalizeStrR = GetCapitalizeStr<"luyaxiang">;

// 把 dong_dong_dong 变换成 dongDongDong
type GetCamelCase<Str extends string> = Str extends `${infer P}_${infer C}${infer L}` ? GetCamelCase<`${P}${Uppercase<C>}${L}`> : Str; // 这里的递归，可以优化为 `${P}${Uppercase<C>}${GetCamelCase<L>}`;因为是从左往后，左侧的肯定都已经替换完成
type GetCamelCaseR = GetCamelCase<"dong_dong_dong">

// 删除字符串中一段字符串
type GetDropSubStr<Str extends string, SubStr extends string> = Str extends `${infer P}${SubStr}${infer L}` ? `${P}${GetDropSubStr<L, SubStr>}` : Str;
type GetDropSubStrR = GetDropSubStr<"123241231", "2">

// ------------------------------------- 函数 -----------------------------------------------
// 在已有的函数类型上添加一个参数
type GetAppendArgument<F extends Function, Arg> = F extends (...args: infer Args) => infer ReturnType ? (...args: [...Args, Arg]) => ReturnType : never;
type A = {age: number;}
type Person = {}
type GetAppendArgumentR = GetAppendArgument<(name: string) => Person, A>

// ------------------------------------- 索引 -----------------------------------------------

// 映射的过程对value做修改
type GetMapping<Obj extends object> = {
  [Key in keyof Obj]: [[Obj[Key]], [Obj[Key]], [Obj[Key]]]
}
type GetMappingR = GetMapping<{a: 1, b: 2}>

// 映射的过程对key做修改。下面是把key大写
type GetUpperCaseKey<Obj extends object> = { // 这里把object替换为TS内置的Record，更语义化。Record<string, any>
  [Key in keyof Obj as Uppercase<Key & string>] : Obj[Key]
}
type GetUpperCaseKeyR = GetUpperCaseKey<{a: 1, b: 2}>

// 只读
type GetToReadonly<Obj> = {
  readonly [Key in keyof Obj] : Obj[Key];
}
type GetToReadonlyR = GetToReadonly<{a: 1, b: 2}>

// 可选
type GetToPartial<Obj> = {
  [Key in keyof Obj]?: Obj[Key];
}

// 去掉只读readonly修饰符
type GetToMutable<Obj> = {
  -readonly [Key in keyof Obj]: Obj[Key];
}

// 去掉可选修饰符
type GetToRequired<Obj> = {
  [Key in keyof Obj]-?: Obj[Key];
}

// 根据值的类型做过滤

type GetFilterByValueType<Obj extends Record<string, any>, ValueType> = {
  [Key in keyof Obj as Obj[Key] extends ValueType ? Key : never]: Obj[Key]
}
type GetFilterByValueTypeR = GetFilterByValueType<{a: 1, b: "s", c: true}, string | number>

























